import { HttpError, OrgData, RuntimeError } from '@ibiz-template/core';
import { IAppView, IApplication } from '@ibiz/model-core';
import { mergeDeepRight } from 'ramda';
import { ModelLoaderProvider } from '@ibiz-template/runtime';
import { AppHooks } from '@ibiz-template/vue3-util';

export class AuthGuard {
  /**
   * 是否是全代码模式
   * @author lxm
   * @date 2024-02-21 11:16:08
   * @type {boolean}
   */
  isFullCode: boolean = false;

  /**
   * 自定义模型加载
   * @author lxm
   * @date 2024-02-21 11:16:17
   * @type {ModelLoaderProvider}
   */
  customModelLoader?: ModelLoaderProvider;

  constructor(opts?: {
    isFullCode: boolean;
    customModelLoader: ModelLoaderProvider;
  }) {
    this.isFullCode = opts?.isFullCode || false;
    this.customModelLoader = opts?.customModelLoader || undefined;

    if (this.customModelLoader) {
      ibiz.hub.registerModelLoaderProvider(this.customModelLoader);
    }
  }

  /**
   * 总的入口校验
   * @author lxm
   * @date 2024-02-21 10:43:55
   * @param {boolean} notLogin
   * @return {*}  {Promise<boolean>}
   */
  async verify(notLogin: boolean = true): Promise<boolean> {
    if (notLogin) {
      let result = true;

      try {
        // 开启匿名模式的时候，进行匿名相关的校验和处理
        if (ibiz.env.enableAnonymous) {
          await this.anonymousValidate();
        }

        await this.appInit();
      } catch (error) {
        result = false;
        ibiz.util.error.handle(error);
      }
      return result;
    }
    await this.initModel(false);
    return true;
  }

  /**
   * 匿名登录相关校验逻辑，不通过会抛异常
   * @author lxm
   * @date 2024-01-03 07:29:30
   * @return {*}  {Promise<void>}
   */
  async anonymousValidate(): Promise<void> {
    const authInfo = ibiz.auth.getAuthInfo();
    if (authInfo && !authInfo.isAnonymous) {
      // 有正常用户已经登录的情况，直接跳过后续逻辑
      return;
    }

    // 走匿名用户模式的处理
    // 加载simple模型
    await this.initModel(false);

    const urlPaths = window.location.hash.split('/');
    const viewName = urlPaths[urlPaths.length - 2];
    let viewModel: IAppView | undefined;
    if (viewName !== '#') {
      try {
        viewModel = await ibiz.hub.getAppView(viewName);
      } catch (error) {
        ibiz.log.error(error);
      }
    }
    if (!viewModel) {
      // 找不到视图说明没有配置匿名访问的视图
      ibiz.log.error(
        `找不到视图模型${viewName},请确保该视图配置了匿名访问和用户引用`,
      );
      this.throw401();
      return;
    }

    // 非匿名用户能访问的视图直接抛出401
    if (viewModel.accUserMode !== 3) {
      this.throw401();
    }

    // 匿名用户登录
    if (!authInfo) {
      const loginResult = await ibiz.auth.anonymousLogin();
      if (!loginResult) {
        throw new RuntimeError('匿名用户登录失败');
      }
    }
  }

  /**
   * 应用参数初始化
   *
   * @author chitanda
   * @date 2022-07-20 19:07:54
   * @return {*}  {Promise<void>}
   */
  async appInit(): Promise<void> {
    if (ibiz.env.isSaaSMode === true) {
      await this.loadOrgData();
    }
    await this.loadAppData();
    await this.initModel();
    await ibiz.auth.extendLogin();
    await ibiz.hub.notice.init();
  }

  /**
   * 初始化模型
   * @author lxm
   * @date 2024-02-21 10:48:36
   * @param {boolean} [permission=true]
   * @return {*}  {Promise<void>}
   */
  async initModel(_permission: boolean = true): Promise<void> {
    // 子类实现
  }

  /**
   * 加载应用数据
   *
   * @author chitanda
   * @date 2022-07-20 20:07:50
   * @return {*}  {Promise<void>}
   */
  async loadAppData(): Promise<void> {
    const res = await ibiz.net.get('/appdata');
    if (res.ok) {
      ibiz.appData = res.data;
    }
  }

  /**
   * 加载组织数据
   *
   * @author chitanda
   * @date 2022-07-20 20:07:44
   * @return {*}  {Promise<void>}
   */
  async loadOrgData(): Promise<void> {
    const res = await ibiz.net.get(`/uaa/getbydcsystem/${ibiz.env.dcSystem}`);
    if (res.ok) {
      const orgDataItems = res.data as OrgData[];
      if (orgDataItems) {
        const [data] = orgDataItems;
        ibiz.orgData = data;
      }
    }
  }

  async initTheme(appModel: IApplication): Promise<void> {
    if (!appModel.appUIThemes) {
      const module = await import('@ibiz-template/web-theme');
      const theme = module.default || module;
      AppHooks.useComponent.callSync(null, theme);
    } else {
      await this.loadTheme();
    }
  }

  /**
   * 加载主题插件
   *
   * @author chitanda
   * @date 2023-12-03 01:12:38
   * @protected
   * @return {*}  {Promise<void>}
   */
  async loadTheme(): Promise<void> {
    const app = ibiz.hub.getApp();
    const uiThemes = app.model.appUIThemes || [];
    if (uiThemes.length > 0) {
      const theme = uiThemes[0];
      await ibiz.util.theme.loadTheme(theme);
    }
  }

  /**
   * 根据应用自定义参数解析成环境变量
   *
   * @author chitanda
   * @date 2023-11-24 19:11:50
   * @return {*}  {Promise<void>}
   */
  async initEnvironment(app: IApplication): Promise<void> {
    const userParam = app.userParam;
    if (userParam) {
      Object.keys(userParam).forEach(key => {
        const value = ibiz.util.rawValue.format(userParam[key]);
        const keys = key.split('.');
        let currentObj = ibiz.env as IData;
        for (let i = 0; i < keys.length; i++) {
          const k = keys[i];
          if (i === keys.length - 1) {
            currentObj[k] = value;
          } else {
            currentObj[k] = currentObj[k] || {};
            currentObj = currentObj[k];
          }
        }
      });
      if (ibiz.env.globalConfig) {
        ibiz.config = mergeDeepRight(ibiz.config, ibiz.env.globalConfig);
      }
      // 重新设置日志级别
      ibiz.log.setLevel(ibiz.env.logLevel);
    }
  }

  throw401(): void {
    throw new HttpError({
      response: {
        status: 401,
        statusText: '无权限访问！',
      },
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
    } as any);
  }
}
